#include "cflow.hpp"

using namespace std;

CFlowSmart::CFlowSmart() { flag_is_ok = 0; sentit = -1; }
        
//void CFlowSmart::read_ascii_header(FILE *fd)
//{
//	char buffer[255];
//	uint32_t stop = 0;
//	
//	while (!feof(fd) && !stop)
//	{
//		fgets(buffer, sizeof(buffer), fd);
//		printf("%d|%s", strlen(buffer), buffer);
//        stop |= (uint32_t) strstr(buffer, "#binary data follows");
//		stop |= (uint32_t) strstr(buffer,"#src\tdst\tproto\tok\tsport\tdport\tpkts\tbytes\tflows\tfirst\tlatest");
//	}
//}

///* return 1 if read succesfully, 0 otherwise */
//int CFlowSmart::read_bin(struct SFlow_smart *a, FILE *fd)
//{
//    char buffer[56];
//    uint8_t longitud, full_save;
//    
//    fread(buffer, sizeof(buffer), 1, fd);    
//
//    longitud   = *(uint8_t *)buffer;
//    full_save  = *(uint8_t *)(buffer+1);
//    if ((longitud != 14) || (full_save != 1)) return 0;    
//    a->ip_src     = *((struct in_addr *)(buffer+2));
//    a->ip_dst     = *((struct in_addr *)(buffer+6));
//    a->ip_proto   = *(uint8_t *)(buffer+10);
////    a->ports_ok   = *(uint8_t *)(buffer+11);
//    a->sport      = *((uint16_t *)(buffer+12));
//    a->dport      = *((uint16_t *)(buffer+14));
//    a->pkts       = *((uint64_t *)(buffer+16));
//    a->bytes      = *((uint64_t *)(buffer+24));
//    a->flows      = *((uint64_t *)(buffer+32));
////    a->first_sec  = ntohl(*((uint32_t *)(buffer+40)));
////    a->first_nsec = ntohl(*((uint32_t *)(buffer+44)));
////    a->last_sec   = ntohl(*((uint32_t *)(buffer+48)));
////    a->last_nsec  = ntohl(*((uint32_t *)(buffer+52)));
//
//    return 1;
//}

int CFlowSmart::read_bin2(struct SFlow_smart *a, FILE *fd)
{
    char buffer[56], linia[255];
    uint8_t longitud, full_save;
    int i;
    
    if((fread(buffer, sizeof(buffer), 1, fd))<= 0){
        return 0;
    }
    
    longitud   = *(uint8_t *)buffer;
    full_save  = *(uint8_t *)(buffer+1);
    if (buffer[0] == '#')
    {
        fseek(fd, -1*(sizeof(buffer)), SEEK_CUR);
        fgets(linia, 255, fd);
//                    cout << linia; // DEBUG 
        if(strstr((char*) linia, "begin Tuple Table (expired) ID: 0[0]")) sentit = 0;
        else if(strstr((char*) linia, "begin Tuple Table (expired) ID: 1[0]")) sentit = 1;
        else if(strstr((char*) linia, "end of text table")) return 0;
    }
    else if (sentit == -1 ) { /*my patch, to skip empty lines in the header of the file */
        /* if direction not yet detected, skip empty lines */
        fseek(fd, -1*(sizeof(buffer)), SEEK_CUR);
        fgets(linia, 255, fd);
//                cout << "EMPTY LINE" << endl; // DEBUG
        return 0;
    }
    else if ((longitud != 14) || (full_save != 1)) {
        return 0;
    }
    else
    {
        a->ip_src     = *((struct in_addr *)(buffer+2));
        a->ip_dst     = *((struct in_addr *)(buffer+6));

//                cout << " read src " << inet_ntoa(a->ip_src) << endl; // DEBUG
//                cout << " read dst " << inet_ntoa(a->ip_dst) << endl; // DEBUG

        a->ip_proto   = *(uint8_t *)(buffer+10);
//                a->ports_ok   = *(uint8_t *)(buffer+11);
        a->sport      = *((uint16_t *)(buffer+12));
        a->dport      = *((uint16_t *)(buffer+14));
        a->pkts       = *((uint64_t *)(buffer+16));
        a->bytes      = *((uint64_t *)(buffer+24));
        a->flows      = *((uint64_t *)(buffer+32));
//                a->first_sec  = ntohl(*((uint32_t *)(buffer+40)));
//                a->first_nsec = ntohl(*((uint32_t *)(buffer+44)));
//                a->last_sec   = ntohl(*((uint32_t *)(buffer+48)));
//                a->last_nsec  = ntohl(*((uint32_t *)(buffer+52)));

        return 1;
    }
    return 0;
}

/* if fname = "-", then use stdin */
int CFlowSmart::open( string fname )
{
    if ( fname == "-" ) {
        fd = stdin;
    }
    else {
        fd = fopen( fname.c_str() , "r");
    }
    if ( fd == NULL ) return -1;
//            read_ascii_header(fd); // TODO check error
    flag_is_ok = 1;
    return 0;
}

void CFlowSmart::close()
{
    if ( fd != stdin ) fclose(fd);
    fd = NULL;
}

/* return 1 if fetched succesfully, 0 otherwise */
int CFlowSmart::next()
{
    if ( feof(fd) ) return 0;
    if ( read_bin2(&flowbin, fd) ) {
//                cout << " read src " << inet_ntoa(flowbin.ip_src) << endl; // DEBUG
//                cout << " read dst " << inet_ntoa(flowbin.ip_dst) << endl; // DEBUG
        return 1;
    }
    else return 0;
}

int CFlowSmart::is_ok() { return flag_is_ok; }
int CFlowSmart::is_end() { return feof(fd); }


struct   in_addr CFlowSmart::getAddrSrc() { return flowbin.ip_src; }
struct   in_addr CFlowSmart::getAddrDst() { return flowbin.ip_dst; }
uint64_t CFlowSmart::getFlows()         { return flowbin.flows;  }
uint64_t CFlowSmart::getOctets()        { return flowbin.bytes;  }
uint64_t CFlowSmart::getPackets()       { return flowbin.pkts;   }
uint16_t CFlowSmart::getPortSrc()       { return flowbin.sport;  }
uint16_t CFlowSmart::getPortDst()       { return flowbin.dport;  }


CFlowNF::CFlowNF()
{
    flag_is_ok = 0;
    fd_in = 0; /*stdin*/
}

int CFlowNF::open( string fname )
{
    /* init fterr */
//    fterr_setid(argv[0]);
    fterr_setid( "txas++" );
    bzero(&ftv, sizeof ftv);

    if ( fname != "-" ) {
       if ( (fd_in = ::open( fname.c_str(), O_RDONLY, 0) ) == -1) {
           return -1;
       }
    }
    else {
        fd_in = 0;
    }

    /* read from stream */
    if (ftio_init(&ftio, fd_in , FT_IO_FLAG_READ) < 0) fterr_errx(1, "ftio_init(): failed");

    ftio_get_ver(&ftio, &ftv);
    ftv.s_version = FT_IO_SVERSION;
    fts3rec_compute_offsets(&fo, &ftv);

//    print_header();
//    action_traffic_as_as(hashtable_traffic_matrix);
//    g_hash_table_foreach(hashtable_traffic_matrix, display_tx_record_fn, NULL);
//    print_footer();

//    if (fd_out != stdout) fclose(fd_out);
//    return ftio_close(&ftio);

    flag_is_ok = 1;
    flag_end = 0;
    return 0;
}

void CFlowNF::close()
{
//    if (fd_out != stdout) fclose(fd_out);
    ftio_close(&ftio);
    if ( fd_in != 0) ::close(fd_in);
//    return ftio_close(&ftio);
}

int CFlowNF::next()
{
    uint64_t octets, packets;

    rec = (char*) ftio_read(&ftio);
    if ( !rec ) {
        flag_end = 1;
        return 0;
    }

     cur.srcaddr   = ((u_int32*)(rec+fo.srcaddr));
     cur.dstaddr   = ((u_int32*)(rec+fo.dstaddr));
     cur.src_as    = ((u_int16*)(rec+fo.src_as));
     cur.dst_as    = ((u_int16*)(rec+fo.dst_as));
     cur.dPkts     = ((u_int32*)(rec+fo.dPkts));
     cur.dOctets   = ((u_int32*)(rec+fo.dOctets));
     cur.prot      = ((u_int8 *)(rec+fo.prot));
     cur.unix_secs = ((u_int32*)(rec+fo.unix_secs));
     cur.srcport   = ((u_int16*)(rec+fo.srcport));
     cur.dstport   = ((u_int16*)(rec+fo.dstport));

//     cur.unix_nsecs = ((u_int32*)(rec+fo.unix_nsecs));
//     cur.sysUpTime  = ((u_int32*)(rec+fo.sysUpTime));

//    packets = *cur.dPkts;
//    octets  = *cur.dOctets;


    address_src.s_addr = ntohl( *cur.srcaddr ) ; // !!! TODO CHECK IF PROPER ORDER!
    address_dst.s_addr = ntohl( *cur.dstaddr ) ; // !!! TODO CHECK IF PROPER ORDER!

    return 1;
}

struct in_addr CFlowNF::getAddrSrc()
{
    return address_src;
}
struct in_addr CFlowNF::getAddrDst()
{
    return address_dst;
}

uint64_t CFlowNF::getFlows()
{
    return 1;
}

uint64_t CFlowNF::getOctets()
{
    return *cur.dOctets;
}

uint64_t CFlowNF::getPackets()
{
    return *cur.dPkts;
}

uint16_t CFlowNF::getPortSrc()
{
    return *cur.srcport;
}

uint16_t CFlowNF::getPortDst()
{
    return *cur.dstport;
}

int CFlowNF::is_ok()
{
    return flag_is_ok;
}

int CFlowNF::is_end()
{
    return flag_end;
}

uint16_t CFlowNF::getAsnSrc()
{
    return *cur.src_as;
}

uint16_t CFlowNF::getAsnDst()
{
    return *cur.dst_as;
}

